#include "Socket.hpp"
#include <iostream>
#include "Tcpserver.hpp"
#include "InetAddr.hpp"
#include <memory>
#include "Log.hpp"
#include <unordered_map>
#include "Uitl.hpp"
#include <sstream>
const std::string http_space = " ";
const std::string http_line_feed = "\r\n";
const std::string http_sep = ": ";

const std::string pga_404 = "404.html";
const std::string webroot = "./webroot";
const std::string home = "index.html";

class HttpRequset
{
public:
    HttpRequset() : _blankline(http_line_feed)
    {
    }
    ~HttpRequset() {}

    // 序列化
    void HttpSerialize()
    {
        // 把所有属性按照协议规定打包成字符串
    }

    void ReqDeserLine(std::string &reqline)
    {
        std::stringstream ss(reqline);
        ss >> _method >> _uri >> _versions;
    }
    // 反序列化
    bool HttpDeserialization(std::string &reqstring)
    {
        // 先获取第一行请求行
        std::string reqline;
        bool ret = Uitl::ReadReqOneStr(reqstring, &reqline);
        // 将请求行反序列化
        ReqDeserLine(reqline);

        if (_uri == "/") // 因为在返回网页时浏览器会自动拼接该网页的上级目录，也成为web根目录
        {
            _uri = webroot + "/" + home;
        }
        else
        {
            _uri = webroot + _uri;
        }
        size_t pos;
        while ((pos = _uri.find("//")) != std::string::npos)
        {
            _uri.replace(pos, 2, "/");
        }
        LOG(LogLevel::DEBUG) << "_method: " << _method;
        LOG(LogLevel::DEBUG) << "_uri: " << _uri;
        LOG(LogLevel::DEBUG) << "_version: " << _versions;

        return true;
    }
    std::string Uri() { return _uri; }

private:
    std::string _method;                                  // 请求方法
    std::string _uri;                                     // 请求目标，需要访问什么
    std::string _versions;                                // 浏览器的版本，默认1.0
    std::unordered_map<std::string, std::string> _header; // 请求报头，Content-Length，Content-Type
    std::string _blankline;                               // 空白行
    std::string _text;                                    // 正文
};

class HttpResponse
{
public:
    HttpResponse() : _blankline(http_line_feed), _versions("HTTP/1.0")
    {
    }
    ~HttpResponse() {}

    //将需要发送的请求序列化
    std::string HttpSerialize()
    {
        std::string status_line = _versions + http_space + std::to_string(_code) + http_space + _desc + http_line_feed; // 状态行

        std::string res_header;
        for (auto &head : _header)
        {
            res_header = head.first + http_sep + head.second + http_line_feed;
        }
        return status_line + res_header + _blankline + http_line_feed + _text;
    }
    //对需要访问资源的路径进行提取
    void SetTargerFile(std::string targer)
    {
        _targetfile = targer;
    }
    //根据访问的资源设置状态码与状态码描述
    void SetCode(int code)
    {
        _code = code;
        switch (_code)
        {
        case 200:
            _desc = "OK";
            break;
        case 404:
            _desc = "Not Found";
            break;
        default:
            break;
        }
    }
    //根据报文内容设置报头属性
    void SetHeader(const std::string &key, const std::string &value)
    {
        auto iter = _header.find(key);
        if (iter != _header.end())
            return;
        _header.insert(std::make_pair(key, value));
    }
    //构建一个应答
    bool MakeResponse()
    {
        if (_targetfile == "./wwwroot/favicon.ico")
        {
            LOG(LogLevel::DEBUG) << "用户请求: " << _targetfile << "忽略它";
            return false;
        }
        // 对请求字符串，进行反序列化
        // 还可以通过对uri路径需要访问的资源做解析，判断需要访问什么类型的资源
        // 再将Content-Type的值改为对应类型
        int filesize = 0;
        bool res = Uitl::ReadFileText(_targetfile, &_text);
        if (!res)
        {
            _text = "";
            SetCode(404);
            _targetfile = webroot + "/" + pga_404; // 直接跳转到404页面
            Uitl::ReadFileText(_targetfile, &_text);
            filesize = Uitl::FileSize(_targetfile);

            SetHeader("Content-Type", "text/html");
            SetHeader("Content-Length", std::to_string(filesize));
        }
        else
        {
            LOG(LogLevel::DEBUG) << "读取文件: " << _targetfile;
            SetCode(200);
            filesize = Uitl::FileSize(_targetfile);
            SetHeader("Content-Type", "text/html");
            SetHeader("Content-Length", std::to_string(filesize));
        }
        return true;
    }

private:
    std::string _versions; // 版本号
    int _code;             // 状态码
    std::string _desc;     // 状态描述符

    std::unordered_map<std::string, std::string> _header;

    std::string _blankline;
    std::string _text;

    std::string _targetfile;
};

class Http
{
public:
    Http(uint16_t port) : _tsvrp(std::make_unique<Tcpserver>(port))
    {
    }
    // 需要把浏览器发过来的字符串反序列化
    void HandlerHttpRquest(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        std::string httpreqstr;
        int n = sock->Recv(&httpreqstr);
        std::cout << httpreqstr << std::endl;
        if (n > 0)
        {

            HttpRequset req;
            req.HttpDeserialization(httpreqstr);
            HttpResponse resp;
            resp.SetTargerFile(req.Uri());
            if (resp.MakeResponse())
            {
                std::string resp_str = resp.HttpSerialize();
                std::cout<<resp_str<<std::endl;
                int n = sock->Send(resp_str);
            }
        }
        else
        {
            return;
        }
    }

    void Start()
    {
        _tsvrp->Start([this](std::shared_ptr<Socket> &sock, InetAddr &client)
                      { this->HandlerHttpRquest(sock, client); });
    }

private:
    std::unique_ptr<Tcpserver> _tsvrp;
};